//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
// NOTE: stubs are being used - this isn't done

#include <windows.h>
#include <oal.h>
#include <nkintr.h>
#include "oal_kitl.h"
#include "xllp_defs.h"
#include "xllp_clkmgr.h"
#include "xllp_pm_suspend.h"
#include "xllp_ost.h"
#include "xllp_intc.h"
#include "xllp_gpio_proc.h"
#include "xllp_rtc.h"
#include <pkfuncs.h>
#include "monahans_base_regs.h"
#include "monahans_rtc.h"
#include "xllp_dfc.h"
#include "xllp_pm.h"
#include "SleepWrkArndWriteReg.h"
#include "ISRAM.h"
#include "xllp_memc.h"

#undef TRACE
#define TRACE   1
#define BSP_RESUME_PARAM1_UA	0xa0000800
#define BSP_RESUME_PARAM2_UA	0xa0000804

extern void InitDebugSerial(UINT32 DbgSerPhysAddr, BOOL fUsePhysical);
void (*pPlatformPreSuspend)() = NULL;

extern unsigned int PmGetCPSR(void);
extern void PmSetCPSR(unsigned int);

//------------------------------------------------------------------------------
//
// Function:     OEMPowerOff
//
// Description:  Called when the system is to transition to it's lowest
//               power mode (off)
//

void OEMCacheRangeFlush(LPVOID pAddr, DWORD dwLength, DWORD dwFlags);

unsigned int g_SRAM_Start = 0x5c010000;


#define 	SLEEP_SAVE_SIZE 32

#define MAX_WAKEUP_SOURCE 32
#define INVALIDATE_SOURCE 0xFFFFFFFF

XLLP_UINT32_T g_WSToIrq[] =
{
	XLLP_INTC_S_EXT1,        	//0
	XLLP_INTC_S_EXT2,        	//1
	INVALIDATE_SOURCE,			//2
	INVALIDATE_SOURCE,			//3
	INVALIDATE_SOURCE,			//4
	XLLP_INTC_S_FFUART,			//5  /* add FF_RI for RIL incoming call wake up source */
	INVALIDATE_SOURCE, 			//6
	INVALIDATE_SOURCE, 			//7
	INVALIDATE_SOURCE, 			//8
	INVALIDATE_SOURCE, 			//9
	INVALIDATE_SOURCE, 			//10
	INVALIDATE_SOURCE,        	//11
	INVALIDATE_SOURCE,			//12
	INVALIDATE_SOURCE,			//13
	INVALIDATE_SOURCE,			//14
	INVALIDATE_SOURCE,			//15
	XLLP_INTC_S_USBC,			//16 USB OTG
	INVALIDATE_SOURCE,			//17
	INVALIDATE_SOURCE,			//18
	XLLP_INTC_S_USIM,			//19
	XLLP_INTC_S_USIM2, 			//20
	XLLP_INTC_S_KEY,			//21
	INVALIDATE_SOURCE,			//22
	INVALIDATE_SOURCE,			//23	
	XLLP_INTC_S_MSL1,			//24
	INVALIDATE_SOURCE,			//25
	XLLP_INTC_S_USB2,			//26
	INVALIDATE_SOURCE,			//27
	XLLP_INTC_S_USBH1,			//28
	XLLP_INTC_S_TSI,			//29
	XLLP_INTC_S_OST,			//30
	XLLP_INTC_S_RTC_ALARM		//31
	
};


typedef struct sleep_content_tag 
{	
	XLLP_PM_DATA_SAVE_T PMData;	
	XLLP_CLKMGR_T Clkmgr;	
	XLLP_OST_T Ost;	
	XLLP_INTC_SAVE_T Intc;	
	XLLP_GPIO_T Gpio;	
	XLLP_RTC_T Rtc;	
	unsigned long SleepSave[SLEEP_SAVE_SIZE];	    
	XLLP_VINT32_T *RegBase[SLEEP_SAVE_SIZE];
	XLLP_UINT32_T	RegCount;
    XLLP_UINT8_T  aucSRAMSave[ISRAM_SAVE_DATA_BYTES];    
} SLEEP_CONTENT;

SLEEP_CONTENT g_SleepContent;

void InitRegBase()
{
	XLLP_VINT32_T **p=g_SleepContent.RegBase;
	*p++=OALPAtoVA(0x4600FE00, FALSE);  // ARB_CNTRL1
	*p++=OALPAtoVA(0x4600FE80, FALSE);  // ARB_CNTRL2

	*p++=OALPAtoVA(0x4A000008, FALSE);  //MSC0 Static Memory Control Register 0
	*p++=OALPAtoVA(0x4A00000C, FALSE);  //MSC1 Static Memory Control Register 1 

	*p++=OALPAtoVA(0x4A000014, FALSE);  //MECR	Expansion Memory (PCMCIA/Compact Flash) Bus Configuration 
	*p++=OALPAtoVA(0x4A00001C, FALSE);  //SXCNFG ynchronous Static Memory Control Register

	*p++=OALPAtoVA(0x4A000028, FALSE);  //MCMEM0 Card interface Common Memory Space Socket 0 Timing
	*p++=OALPAtoVA(0x4A000030, FALSE);  //MCATT0 Card interface Attribute Space Socket 0 Timing Configuration
	*p++=OALPAtoVA(0x4A000038, FALSE);  //MCIO0 Card interface I/O Space Socket 0 Timing Configuration

	*p++=OALPAtoVA(0x4A000068, FALSE);  //MEMCLKCFG SCLK speed configuration
	
	*p++=OALPAtoVA(0x4A000080, FALSE);  //CSADRCFG0  Address Configuration for chip select 0 
	*p++=OALPAtoVA(0x4A000084, FALSE);  //CSADRCFG1  Address Configuration for chip select 1 

	*p++=OALPAtoVA(0x4A000088, FALSE);  //CSADRCFG2  Address Configuration for chip select 2
	*p++=OALPAtoVA(0x4A00008C, FALSE);  //CSADRCFG3  Address Configuration for chip select 3  

	*p++=OALPAtoVA(0x4A000090, FALSE);  //CSADRCFG_P  Address Configuration for pcmcia card interface

	*p++=OALPAtoVA(0x4A0000A0, FALSE);  //CSMSADRCFG   Master Address Configuration Register


	*p++=OALPAtoVA(0x40900008, FALSE);  //RTSR   RTC Status Register

	*p++=OALPAtoVA(0x40900038, FALSE);  //PIAR  Periodic Interrupt Alarm Register


	*p++=OALPAtoVA(0x40F50018, FALSE);  //PECR

	
	g_SleepContent.RegCount=p-g_SleepContent.RegBase;
	
	OALMSGS(TRUE, (L"Save Register Counter %d\r\n",g_SleepContent.RegCount));
	
}

static void FlushCpuCache(void)
{
	OEMCacheRangeFlush(NULL, 0, CACHE_SYNC_WRITEBACK);
}

#define OSCR_OFFSET           0x10

static void Wait(UINT32 microSeconds)
{
#if MINI_EBOOT
    volatile UINT32 *TimerOSCRAddress= (volatile UINT32 *)(MONAHANS_BASE_REG_PA_OST + OSCR_OFFSET);
#else
    volatile UINT32 *TimerOSCRAddress= (volatile UINT32 *) OALPAtoVA((MONAHANS_BASE_REG_PA_OST + OSCR_OFFSET), FALSE);
#endif

    UINT32 Value, Time;

    Time   = *TimerOSCRAddress;
    Value = Time + (microSeconds * 4);
    if (Value < Time)
    {  // test for wrap.
        while (Time < *TimerOSCRAddress);
    }
    while (*TimerOSCRAddress <= Value);

}

static void msWait(UINT32 msVal) 
{
    Wait(msVal*1000);
}

void SetWakeupSource()
{

	UINT32 *pIrqs, i, j,count, sysIntr;
	XLLP_PM_SPMU_T  *pSPMReg=NULL; 
	XLLP_PM_BPMU_T  *pBPMUReg=NULL;

	pSPMReg = OALPAtoVA(MONAHANS_BASE_REG_PA_SPMU, FALSE);
	pBPMUReg = OALPAtoVA(MONAHANS_BASE_REG_PA_BPMU, FALSE);
	
	pSPMReg->pwer = 0;
	pBPMUReg->ad3er =0;
	
	for (sysIntr = SYSINTR_DEVICES; sysIntr < SYSINTR_MAXIMUM; sysIntr++) 
	{
        if (!OALPowerWakeSource(sysIntr))
            continue;                                               // Skip if sysIntr isn't allowed as wake source
        if (!OALIntrTranslateSysIntr(sysIntr, &count, &pIrqs))
            continue;                                                // Get IRQs

			
        for (i = 0; i < count; i++) 
		{                              // Hardware supports only restricted number of sources
            for(j=0;j<MAX_WAKEUP_SOURCE;j++)
            {
            	if(g_WSToIrq[j] == pIrqs[i] )
            	{
            		pBPMUReg->ad3er |= 1<<j;
            	}
            }
        }
    }


	pSPMReg->pwer |=   0x80000005; // enable EXT_WAKEUP0 rising edge wake up

	pBPMUReg->ad3er |= 0x80000001; //enable RTC Alarm wakeup and EXT_WAKEUP0 edge detect

	OALMSGS(TRUE, (L"PWER::0x%x AD3ER:0x%x\r\n", pSPMReg->pwer , pBPMUReg->ad3er ));  

       // Delay to let the setup take effect, 5ms delay
	msWait(5);
	OALMSGS(TRUE, (L"setup wakeup source, 5 ms delay to take effect. \r\n"));  

	//NKDbgPrintfW(TEXT("PWER***: 0x%x AD3ER:0x%x\r\n"), pSPMReg->pwer , pBPMUReg->ad3er);
	//NKDbgPrintfW(TEXT("PWER***: Hardcoding FFUART wakeup for now. Needs clean up"));
	//pBPMUReg->ad3er |= 1<<5; //enable FFUART wakeup WE_GENERIC[3]
	//NKDbgPrintfW(TEXT("PWER***: 0x%x AD3ER:0x%x\r\n"), pSPMReg->pwer , pBPMUReg->ad3er);
	
}

volatile UINT32 GetWakeupSource()
{
	XLLP_PM_SPMU_T  *pSPMReg=NULL; 
	XLLP_PM_BPMU_T  *pBPMUReg=NULL;
	int i;

	pSPMReg = OALPAtoVA(MONAHANS_BASE_REG_PA_SPMU, FALSE);
	pBPMUReg = OALPAtoVA(MONAHANS_BASE_REG_PA_BPMU, FALSE);

	for( i=0;i<32;i++ )
	{
		if( pBPMUReg->ad3sr & (1<<i))
		{
            if (i==0)
			{
				return SYSWAKE_POWER_BUTTON;
			}
			if( g_WSToIrq[i] != INVALIDATE_SOURCE )
			{
				return OALIntrTranslateIrq(g_WSToIrq[i]);
			}
		}
	}
    
    return SYSWAKE_UNKNOWN;
}



#ifdef EBOOT_BUILD

void DumpMFP(DWORD inPhy, BOOL quiet)
{
    DWORD padNum, *virtual_padNum;
    volatile DWORD *pMFP = (volatile DWORD *)OALPAtoVA(0x40E10000, FALSE);

    padNum=inPhy;
    virtual_padNum =  (DWORD *)OALPAtoVA(padNum, FALSE);

    if(FALSE == quiet)
    {
        EdbgOutputDebugString ("\r\n************************************ Dump MFP *****************************\r\n");
        EdbgOutputDebugString ("\r\nMFPR for Physical Address 0x%x (UVA= 0x%x)  = 0x%x \r\n", padNum, virtual_padNum, *virtual_padNum);
       
        // Decompose the MFPR
        //
        EdbgOutputDebugString ("  MFPR[pull_sel] = 0x%x\r\n", ((*virtual_padNum & (1<<15)) >> 15));
        EdbgOutputDebugString ("  MFPR[pullup_en] = 0x%x\r\n", ((*virtual_padNum & (1<<14)) >> 14));
        EdbgOutputDebugString ("  MFPR[pulldown_en] = 0x%x\r\n", ((*virtual_padNum & (1<<13)) >> 13));
        EdbgOutputDebugString ("  MFPR[drive] = 0x%x\r\n", ((*virtual_padNum & (7<<10)) >> 10));
        EdbgOutputDebugString ("  MFPR[sleep_sel] = 0x%x\r\n", ((*virtual_padNum & (1<<9)) >> 9));
        EdbgOutputDebugString ("  MFPR[sleep_data] = 0x%x\r\n", ((*virtual_padNum & (1<<8)) >> 8));
        EdbgOutputDebugString ("  MFPR[sleep_oe_n] = 0x%x\r\n", ((*virtual_padNum & (1<<7)) >> 7));
        EdbgOutputDebugString ("  MFPR[edge_clear] = 0x%x\r\n", ((*virtual_padNum & (1<<6)) >> 6));
        EdbgOutputDebugString ("  MFPR[edge_fall_en] = 0x%x\r\n", ((*virtual_padNum & (1<<5)) >> 5));
        EdbgOutputDebugString ("  MFPR[edge_rise_en] = 0x%x\r\n", ((*virtual_padNum & (1<<4)) >> 4));
        EdbgOutputDebugString ("  MFPR[AF_Sel] = 0x%x\r\n", ((*virtual_padNum & (7<<0)) >> 0));
        EdbgOutputDebugString ("\r\n************************************ \\Dump MFP *****************************\r\n\r\n");
    }
    else
    {
        EdbgOutputDebugString ("Physical Address 0x%x  = 0x%x \r\n", padNum, *virtual_padNum);
    }
}

void DumpMFPDomain()
{
    UINT16 domain; 
    DWORD startAdxOffset, endAdxOffset, adx;

    while(1)
    {
         startAdxOffset=0; endAdxOffset=0; adx=0;
        
         // this will dump an entire MFP section, grouped by the I/O supply
         //
         EdbgOutputDebugString ("    1: VCC_MEM\r\n");
         EdbgOutputDebugString ("    2: VCC_DF\r\n");
         EdbgOutputDebugString ("    3: VCC_IO3\r\n");
         EdbgOutputDebugString ("    4: VCC_CARD1\r\n");
         EdbgOutputDebugString ("    5: VCC_CARD2\r\n");
         EdbgOutputDebugString ("    6: VCC_IO4\r\n");
         EdbgOutputDebugString ("    7: VCC_CI\r\n");
         EdbgOutputDebugString ("    8: VCC_LCD\r\n");
         EdbgOutputDebugString ("    9: VCC_MSL\r\n");
         EdbgOutputDebugString ("    A: VCC_IO6\r\n");
         EdbgOutputDebugString ("    B: VCC_TSI\r\n");
         EdbgOutputDebugString ("    C: VCC_IO1\r\n");
         EdbgOutputDebugString ("    D: VCC_OSC13M\r\n");
         EdbgOutputDebugString ("    E: VCC_BBAT\r\n");
         EdbgOutputDebugString ("    F: VCC_USB\r\n");
         EdbgOutputDebugString ("    Q: Quit\r\n");
         
         EdbgOutputDebugString ("Choose which supply domain to dump MFPs for: ");
         domain=666;
         while (! ( 
                    ( (domain == '1') ) || ( (domain == '2') )  || ( (domain == '3') )  || ( (domain == '4') )  || ( (domain == '5') ) || 
                    ( (domain == '6') ) || ( (domain == '7') ) || ( (domain == '8') ) || ( (domain == '9') ) || ( (domain == 'A') ) || 
                    ( (domain == 'B') ) || ( (domain == 'C') ) || ( (domain == 'D') ) || ( (domain == 'E') ) || ( (domain == 'F') ) || ( (domain == 'Q') ) 
                    ))
         {
             domain=OEMReadDebugByte();
         }
         EdbgOutputDebugString ("\r\n%c\r\n", domain);
        
         switch(domain)
         {
             case '1':
                 startAdxOffset = 0;
                 endAdxOffset = 0x128;
                 break;
             case '2':
                 startAdxOffset = 0x12C;
                 endAdxOffset = 0x298;
                 break;
             case '3':
                 startAdxOffset = 0x29C;
                 endAdxOffset = 0x2B8;
                 break;
             case '4':
                 startAdxOffset = 0x2BC;
                 endAdxOffset = 0x2D0;
                 break;
             case '5':
                 startAdxOffset = 0x2D4;
                 endAdxOffset = 0x408;
                 break;
             case '6':
                 startAdxOffset = 0x40C;
                 endAdxOffset = 0x458;
                 break;
             case '7':
                 startAdxOffset = 0x45C;
                 endAdxOffset = 0x490;
                 break;
             case '8':
                 startAdxOffset = 0x494;
                 endAdxOffset = 0x4F0;
                 break;
             case '9':
                 startAdxOffset = 0x4F4;
                 endAdxOffset = 0x510;
                 break;
             case 'A':
                 startAdxOffset = 0x514;
                 endAdxOffset = 0x634;
                 break;
             case 'B':
                 // ? docs seem wrong!
                 EdbgOutputDebugString ("TSI under investigation... docs dont make sense\r\n");
                 break;
             case 'C':
                 startAdxOffset = 0x638;
                 endAdxOffset = 0x688;
                 break;
             case 'D':
                 EdbgOutputDebugString ("No VCC_OSC13M MFPR\r\n");
                 break;
             case 'E':
                 EdbgOutputDebugString ("No VCC_BBAT MFPR\r\n");
                 break;
             case 'F':
                 EdbgOutputDebugString ("No VCC_USB MFPR\r\n");
                 break;
             case 'Q':
                 goto DONE;
                 break;
         }
         
         if(endAdxOffset != 0)       // 0 endAdxOffset means no need to run
         {
             for(adx = (0x40E10000 + startAdxOffset); adx <= (0x40E10000 + endAdxOffset); adx += 4)
             {
                 DumpMFP(adx, FALSE);
             }
         }

     } // while(1)

DONE:
    EdbgOutputDebugString ("Domain Dump Complete\r\n");
    return;
}


void DumpMFPDomainAuto()
{
    UINT16 domain; 
    DWORD startAdxOffset, endAdxOffset, adx;

    for(domain=1; domain < 0x10; domain++)
    {
         startAdxOffset=0; endAdxOffset=0; adx=0;

         /*
         // this will dump an entire MFP section, grouped by the I/O supply
         //
         EdbgOutputDebugString ("    1: VCC_MEM\r\n");
         EdbgOutputDebugString ("    2: VCC_DF\r\n");
         EdbgOutputDebugString ("    3: VCC_IO3\r\n");
         EdbgOutputDebugString ("    4: VCC_CARD1\r\n");
         EdbgOutputDebugString ("    5: VCC_CARD2\r\n");
         EdbgOutputDebugString ("    6: VCC_IO4\r\n");
         EdbgOutputDebugString ("    7: VCC_CI\r\n");
         EdbgOutputDebugString ("    8: VCC_LCD\r\n");
         EdbgOutputDebugString ("    9: VCC_MSL\r\n");
         EdbgOutputDebugString ("    A: VCC_IO6\r\n");
         EdbgOutputDebugString ("    B: VCC_TSI\r\n");
         EdbgOutputDebugString ("    C: VCC_IO1\r\n");
         EdbgOutputDebugString ("    D: VCC_OSC13M\r\n");
         EdbgOutputDebugString ("    E: VCC_BBAT\r\n");
         EdbgOutputDebugString ("    F: VCC_USB\r\n");
         EdbgOutputDebugString ("    Q: Quit\r\n");
         
         EdbgOutputDebugString ("Choose which supply domain to dump MFPs for: ");
         domain=666;
         while (! ( 
                    ( (domain == '1') ) || ( (domain == '2') )  || ( (domain == '3') )  || ( (domain == '4') )  || ( (domain == '5') ) || 
                    ( (domain == '6') ) || ( (domain == '7') ) || ( (domain == '8') ) || ( (domain == '9') ) || ( (domain == 'A') ) || 
                    ( (domain == 'B') ) || ( (domain == 'C') ) || ( (domain == 'D') ) || ( (domain == 'E') ) || ( (domain == 'F') ) || ( (domain == 'Q') ) 
                    ))
         {
             domain=OEMReadDebugByte();
         }
         EdbgOutputDebugString ("\r\n%c\r\n", domain);
        */

         switch(domain)
         {
             case 1:
                 startAdxOffset = 0;
                 endAdxOffset = 0x128;
                 break;
             case 2:
                 startAdxOffset = 0x12C;
                 endAdxOffset = 0x298;
                 break;
             case 3:
                 startAdxOffset = 0x29C;
                 endAdxOffset = 0x2B8;
                 break;
             case 4:
                 startAdxOffset = 0x2BC;
                 endAdxOffset = 0x2D0;
                 break;
             case 5:
                 startAdxOffset = 0x2D4;
                 endAdxOffset = 0x408;
                 break;
             case 6:
                 startAdxOffset = 0x40C;
                 endAdxOffset = 0x458;
                 break;
             case 7:
                 startAdxOffset = 0x45C;
                 endAdxOffset = 0x490;
                 break;
             case 8:
                 startAdxOffset = 0x494;
                 endAdxOffset = 0x4F0;
                 break;
             case 9:
                 startAdxOffset = 0x4F4;
                 endAdxOffset = 0x510;
                 break;
             case 0xA:
                 startAdxOffset = 0x514;
                 endAdxOffset = 0x634;
                 break;
             case 0xB:
                 // ? docs seem wrong!
                 //EdbgOutputDebugString ("TSI under investigation... docs dont make sense\r\n");
                 break;
             case 0xC:
                 startAdxOffset = 0x638;
                 endAdxOffset = 0x688;
                 break;
             case 0xD:
                 //EdbgOutputDebugString ("No VCC_OSC13M MFPR\r\n");
                 break;
             case 0xE:
                 //EdbgOutputDebugString ("No VCC_BBAT MFPR\r\n");
                 break;
             case 0xF:
                // EdbgOutputDebugString ("No VCC_USB MFPR\r\n");
                 break;
             case 0x10:
                 goto DONE;
                 break;
         }
         
         if(endAdxOffset != 0)       // 0 endAdxOffset means no need to run
         {
             for(adx = (0x40E10000 + startAdxOffset); adx <= (0x40E10000 + endAdxOffset); adx += 4)
             {
                 DumpMFP(adx, TRUE);
             }
         }

     } // while(1)

DONE:
   // EdbgOutputDebugString ("Domain Dump Complete\r\n");
    return;
}

#else   // BSP build

//RETAILMSG(TRUE, (TEXT("WM9713, Regs[%d] = 0x%X\r\n"), ii, value));
void DumpMFP(DWORD inPhy, BOOL quiet)
{
    DWORD padNum, *virtual_padNum;
    volatile DWORD *pMFP = (volatile DWORD *)OALPAtoVA(0x40E10000, FALSE);

    padNum=inPhy;
    virtual_padNum =  (DWORD *)OALPAtoVA(padNum, FALSE);

    if(FALSE == quiet)
    {
        RETAILMSG(TRUE, (TEXT("\r\n************************************ Dump MFP *****************************\r\n")));
        RETAILMSG(TRUE, (TEXT("\r\nMFPR for Physical Address 0x%x (UVA= 0x%x)  = 0x%x \r\n"), padNum, virtual_padNum, *virtual_padNum));
       
        // Decompose the MFPR
        //
        RETAILMSG(TRUE, (TEXT ("  MFPR[pull_sel] = 0x%x\r\n"), ((*virtual_padNum & (1<<15)) >> 15)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[pullup_en] = 0x%x\r\n"), ((*virtual_padNum & (1<<14)) >> 14)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[pulldown_en] = 0x%x\r\n"), ((*virtual_padNum & (1<<13)) >> 13)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[drive] = 0x%x\r\n"), ((*virtual_padNum & (7<<10)) >> 10)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[sleep_sel] = 0x%x\r\n"), ((*virtual_padNum & (1<<9)) >> 9)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[sleep_data] = 0x%x\r\n"), ((*virtual_padNum & (1<<8)) >> 8)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[sleep_oe_n] = 0x%x\r\n"), ((*virtual_padNum & (1<<7)) >> 7)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[edge_clear] = 0x%x\r\n"), ((*virtual_padNum & (1<<6)) >> 6)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[edge_fall_en] = 0x%x\r\n"), ((*virtual_padNum & (1<<5)) >> 5)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[edge_rise_en] = 0x%x\r\n"), ((*virtual_padNum & (1<<4)) >> 4)));
        RETAILMSG(TRUE, (TEXT ("  MFPR[AF_Sel] = 0x%x\r\n"), ((*virtual_padNum & (7<<0)) >> 0)));
        RETAILMSG(TRUE, (TEXT ("\r\n************************************ \\Dump MFP *****************************\r\n\r\n")));
    }
    else
    {
        RETAILMSG(TRUE, (TEXT ("Physical Address 0x%x  = 0x%x \r\n"), padNum, *virtual_padNum));
    }
}

DWORD MH_LV_MFP_OFFSET_TABLE[] = {
    0x0B4,  0x0B8,  0x0BC,  0x27C,  0x280,  0x284,  0x288,  0x28C,  // MFPRs   0->7
    0x290,  0x294,  0x298,  0x29C,  0x2A0,  0x2A4,  0x2A8,  0x2AC,  // MFPRs   8->15
    0x2B0,  0x2B4,  0x2B8,  0x2BC,  0x2C0,  0x2C4,  0x2C8,  0x2CC,  // MFPRs  16->23
    0x2D0,  0x2D4,  0x2D8,  0x400,  0x404,  0x408,  0x418,  0x41C,  // MFPRs  24->31
    0x420,  0x424,  0x428,  0x42C,  0x430,  0x434,  0x438,  0x43C,  // MFPRs  32->39
    0x440,  0x444,  0x448,  0x44C,  0x450,  0x454,  0x458,  0x45C,  // MFPRs  40->47
    0x460,  0x464,  0x468,  0x46C,  0x470,  0x474,  0x478,  0x47C,  // MFPRs  48->55
    0x480,  0x484,  0x488,  0x48C,  0x490,  0x494,  0x498,  0x49C,  // MFPRs  56->63
    0x4A0,  0x4A4,  0x4A8,  0x4AC,  0x4B0,  0x4B4,  0x4B8,  0x4BC,  // MFPRs  64->71
    0x4C0,  0x4C4,  0x4C8,  0x4CC,  0x4D0,  0x4D4,  0x4D8,  0x4DC,  // MFPRs  72->79
    0x4E0,  0x4E4,  0x4E8,  0x4EC,  0x4F0,  0x4F4,  0x4F8,  0x4FC,  // MFPRs  80->87
    0x500,  0x504,  0x508,  0x50C,  0x510,  0x514,  0x518,  0x51C,  // MFPRs  88->95
    0x520,  0x524,  0x528,  0x600,  0x604,  0x608,  0x60C,  0x610,  // MFPRs  96->103
    0x614,  0x618,  0x61C,  0x620,  0x624,  0x628,  0x62C,  0x630,  // MFPRs 104->111
    0x634,  0x638,  0x63C,  0x640,  0x644,  0x648,  0x64C,  0x650,  // MFPRs 112->119
    0x654,  0x658,  0x65C,  0x660,  0x664,  0x668,  0x66C,  0x670,  // MFPRs 120->127
    0x674,  0x678,  0x2DC,  0x2E0,  0x2E4,  0x2E8,  0x2EC,  0x52C,  // MFPRs  0_2-> 7_2
    0x530,  0x534,  0x538
};

void DumpMFPAutoLv()
{
    // use xlli array to build offsets
    //
    int x;

    char *pMFP = (char *)0x40E10000;

    for(x=0; x < (sizeof(MH_LV_MFP_OFFSET_TABLE) / 4) ; x++)
    {
        pMFP = (char *)0x40E10000;
        pMFP += MH_LV_MFP_OFFSET_TABLE[x];
        DumpMFP((DWORD)pMFP, TRUE);
    }
}

void DumpMFPDomainAuto()
{
    UINT16 domain; 
    DWORD startAdxOffset, endAdxOffset, adx;

    for(domain=1; domain < 0x10; domain++)
    {
         startAdxOffset=0; endAdxOffset=0; adx=0;

         /*
         // this will dump an entire MFP section, grouped by the I/O supply
         //
         EdbgOutputDebugString ("    1: VCC_MEM\r\n");
         EdbgOutputDebugString ("    2: VCC_DF\r\n");
         EdbgOutputDebugString ("    3: VCC_IO3\r\n");
         EdbgOutputDebugString ("    4: VCC_CARD1\r\n");
         EdbgOutputDebugString ("    5: VCC_CARD2\r\n");
         EdbgOutputDebugString ("    6: VCC_IO4\r\n");
         EdbgOutputDebugString ("    7: VCC_CI\r\n");
         EdbgOutputDebugString ("    8: VCC_LCD\r\n");
         EdbgOutputDebugString ("    9: VCC_MSL\r\n");
         EdbgOutputDebugString ("    A: VCC_IO6\r\n");
         EdbgOutputDebugString ("    B: VCC_TSI\r\n");
         EdbgOutputDebugString ("    C: VCC_IO1\r\n");
         EdbgOutputDebugString ("    D: VCC_OSC13M\r\n");
         EdbgOutputDebugString ("    E: VCC_BBAT\r\n");
         EdbgOutputDebugString ("    F: VCC_USB\r\n");
         EdbgOutputDebugString ("    Q: Quit\r\n");
         
         EdbgOutputDebugString ("Choose which supply domain to dump MFPs for: ");
         domain=666;
         while (! ( 
                    ( (domain == '1') ) || ( (domain == '2') )  || ( (domain == '3') )  || ( (domain == '4') )  || ( (domain == '5') ) || 
                    ( (domain == '6') ) || ( (domain == '7') ) || ( (domain == '8') ) || ( (domain == '9') ) || ( (domain == 'A') ) || 
                    ( (domain == 'B') ) || ( (domain == 'C') ) || ( (domain == 'D') ) || ( (domain == 'E') ) || ( (domain == 'F') ) || ( (domain == 'Q') ) 
                    ))
         {
             domain=OEMReadDebugByte();
         }
         EdbgOutputDebugString ("\r\n%c\r\n", domain);
        */

         switch(domain)
         {
             case 1:
                 startAdxOffset = 0;
                 endAdxOffset = 0x128;
                 break;
             case 2:
                 startAdxOffset = 0x12C;
                 endAdxOffset = 0x298;
                 break;
             case 3:
                 startAdxOffset = 0x29C;
                 endAdxOffset = 0x2B8;
                 break;
             case 4:
                 startAdxOffset = 0x2BC;
                 endAdxOffset = 0x2D0;
                 break;
             case 5:
                 startAdxOffset = 0x2D4;
                 endAdxOffset = 0x408;
                 break;
             case 6:
                 startAdxOffset = 0x40C;
                 endAdxOffset = 0x458;
                 break;
             case 7:
                 startAdxOffset = 0x45C;
                 endAdxOffset = 0x490;
                 break;
             case 8:
                 startAdxOffset = 0x494;
                 endAdxOffset = 0x4F0;
                 break;
             case 9:
                 startAdxOffset = 0x4F4;
                 endAdxOffset = 0x510;
                 break;
             case 0xA:
                 startAdxOffset = 0x514;
                 endAdxOffset = 0x634;
                 break;
             case 0xB:
                 // ? docs seem wrong!
                 //EdbgOutputDebugString ("TSI under investigation... docs dont make sense\r\n");
                 break;
             case 0xC:
                 startAdxOffset = 0x638;
                 endAdxOffset = 0x688;
                 break;
             case 0xD:
                 //EdbgOutputDebugString ("No VCC_OSC13M MFPR\r\n");
                 break;
             case 0xE:
                 //EdbgOutputDebugString ("No VCC_BBAT MFPR\r\n");
                 break;
             case 0xF:
                // EdbgOutputDebugString ("No VCC_USB MFPR\r\n");
                 break;
             case 0x10:
                 goto DONE;
                 break;
         }
         
         if(endAdxOffset != 0)       // 0 endAdxOffset means no need to run
         {
             for(adx = (0x40E10000 + startAdxOffset); adx <= (0x40E10000 + endAdxOffset); adx += 4)
             {
                 DumpMFP(adx, TRUE);
             }
         }

     } // while(1)

DONE:
    RETAILMSG(TRUE, (TEXT ("Domain Dump Complete\r\n")));
    return;
}

#endif  //ebott_build

#define MHLV_A2_WA_SAVE_RESTORE_OSCR0 1
#ifdef MHLV_A2_WA_SAVE_RESTORE_OSCR0
    XLLP_VUINT32_T    oscr0_saved;
	XLLP_VUINT32_T    oscr4_saved;
#endif

void OEMPowerOff()
{
    unsigned int	i=0;
    XLLP_PM_SPMU_T  *pSPMReg=NULL; 
    XLLP_PM_BPMU_T  *pBPMUReg=NULL;
    volatile XLLP_CLKMGR_T *pCLKS 		= (volatile XLLP_CLKMGR_T *)OALPAtoVA(MONAHANS_BASE_REG_PA_CLKMGR, FALSE);
#if 0
    volatile DWORD temp;
#endif
    BOOL bSideCarEnabled=FALSE;
    BOOL bSramEnabled = FALSE;

    volatile UINT32     *pMFPBase = (volatile UINT32 *)OALPAtoVA(MONAHANS_BASE_REG_PA_MFP, FALSE);
    volatile UINT32     *pMFP_I2C_SCL = pMFPBase + 0x2C4;
    volatile UINT32     *pMFP_I2C_SDA = pMFPBase + 0x2C8;
    volatile UINT32     *pOSCCReg = (volatile UINT32 *)OALPAtoVA(MONAHANS_BASE_REG_PA_OSCC, FALSE);		

	XLLP_RTC_T    *pRTC=NULL;

#ifdef RTC_WAKEUP_TEST
	DWORD rcnt;
#endif

#ifdef ENABLE_RCOMP
    XLLP_MEMC_T memc;
#endif

#ifdef MHLV_A2_WA_SAVE_RESTORE_OSCR0
    volatile XLLP_OST_T * pOST= (volatile XLLP_OST_T  * ) OALPAtoVA(MONAHANS_BASE_REG_PA_OST, FALSE);
#endif

    bSramEnabled = EnableSRAM();

    /* Check if it need to back up the SRAM content */
    if (bSramEnabled)
    {
        /*Before sleep, back up the SRAM content which had been used only in IMM driver */
        SaveSRAMDataToDDR(g_SleepContent.aucSRAMSave, sizeof(g_SleepContent.aucSRAMSave));
    }

    // enable boot rom clock
    XllpClockEnable((P_XLLP_CLKMGR_T)pCLKS, XLLP_CLK_BOOT, XLLP_TRUE);


	pSPMReg = OALPAtoVA(MONAHANS_BASE_REG_PA_SPMU, FALSE);
	pBPMUReg = OALPAtoVA(MONAHANS_BASE_REG_PA_BPMU, FALSE);
	pRTC=OALPAtoVA(MONAHANS_BASE_REG_PA_RTC, FALSE);
     
	InitRegBase();
	
	for(i=0;i<g_SleepContent.RegCount;i++)
	{
		g_SleepContent.SleepSave[i]= *g_SleepContent.RegBase[i];
	}

	/*save clock manager registers */
	XllpClockSave(OALPAtoVA(MONAHANS_BASE_REG_PA_CLKMGR, FALSE), &(g_SleepContent.Clkmgr));	

	
	/*save interrupt controller register */	
	XllpINTCSave(OALPAtoVA(MONAHANS_BASE_REG_PA_INTC,FALSE), &(g_SleepContent.Intc));	

	/*save GPIO registers */	
	XllpGpioSave(OALPAtoVA(MONAHANS_BASE_REG_PA_GPIO,FALSE), &(g_SleepContent.Gpio));		

	/*initialize XLLP_PM_DATA_SAVE_T */	
	/* should set:modeSaveFlags, areaAddress, flushFunc, psprAddress,	 * copySramFunc, sramAddress, extendedChecksumByteCount */	

	g_SleepContent.PMData.modeSaveFlags = 0x3f;//XLLP_PM_MODE_SAVE_FLAG_SVC;	
	g_SleepContent.PMData.areaAddress = (unsigned long)&(g_SleepContent.PMData);	
	g_SleepContent.PMData.flushFunc = FlushCpuCache;	
	g_SleepContent.PMData.psprAddress = (unsigned long)&(pSPMReg->pspr);	
	
	//content->pm_data->sramAddress = sram_start;	
	//content->pm_data.copySramFunc = copy_bootcode_to_sram;	
	g_SleepContent.PMData.extendedChecksumByteCount = sizeof(SLEEP_CONTENT)- sizeof(XLLP_PM_DATA_SAVE_T);	

	// setup ext_wakeup1 as rising and falling edge wake-up source
	// config pwer register
	//*((XLLP_VUINT32_T *)OALPAtoVA(0x43000010, FALSE)) |= 0xd;// masked by Andre

	// get access permission of 0x5c010000 from CADDO	
	g_SRAM_Start =(unsigned int) OALPAtoVA(MONAHANS_BASE_REG_PA_IMSTORAGE+0x14000, FALSE);	 

	OALMSGS(TRUE, (L"g_SRAM_Start is :0x%x\r\n", g_SRAM_Start));    
	
	/* save the resume back address into DDR SDRAM */	
	OALMSGS(TRUE, (L"Finish init save content\r\n"));	
	
	*(UINT32 *)(BSP_RESUME_PARAM1_UA)     = OALVAtoPA(XllpPmResumeFromSleep);	
	*(UINT32 *)(BSP_RESUME_PARAM2_UA) = OALVAtoPA(&(g_SleepContent.PMData));	
	
	/* clear PWSR */
	pSPMReg->pwsr = 	pSPMReg->pwsr;

	/* clear and set PECR */	
	pSPMReg->pecr = pSPMReg->pecr;	
	pSPMReg->pecr |= 0x1<<28;	
	//pSPMReg->pecr &= 0xA0000000;	// masked by Andre

	/* clear ASCR, ARSR */	
	pBPMUReg->ascr = 	pBPMUReg->ascr;
	pBPMUReg->arsr = 	pBPMUReg->arsr;


	/* Ensure CLK_POUT is disabled*/
	*pOSCCReg = 0x1E5;
	//OALMSGS(TRUE, (L"OEMPowerOff:Ensure CLK_POUT is disabled\r\n"));	

	/* Set Pull-Ups on I2C Lines for sleep mode*/
      // this has been done in XllpPmEnterSleep function
	*pMFP_I2C_SCL = 0x141;
	*pMFP_I2C_SDA = 0x141;
	//OALMSGS(TRUE, (L"OEMPowerOff:Set Pull-Ups on I2C Lines for sleep mode\r\n"));	

      /* Enable DC-DC regulator in Deep Sleep
      Set L1_DIS bit to 1.  Set L1_DIS bit to 1.  L0_EN determines source for S2.
      L0_EN determines source for S2.*/
      pSPMReg->pcfr |= 0x2000;
      /*Set L0_EN bit to 0.  The DC-DC converter is used in S2 and S3.*/
      pSPMReg->pcfr &= ~(0x1<<12);
	//OALMSGS(TRUE, (L"OEMPowerOff:Enable DC-DC regulator in Deep Sleep\r\n"));	

      /* Set SRAM retention while in S2. All SRAM / L2  ON*/
	pBPMUReg->ad3r = 0x01FF;
	//OALMSGS(TRUE, (L"OEMPowerOff:Set SRAM retention while in S2\r\n"));	
	/* make sure that sram bank 0 is not off */	
	//pBPMUReg->ad3r |= 0x1; // masked


	// can be wake up by RTC and EXT_WAKEUP[0,1] from sevice unit.	 
	// EXT_WAKEUP[0] connects SW6 and EXT_WAKEUP[1] connects IRQ_N of PMIC.	
	// pSPMReg->pwer = 0xF;
	
	// PWER = 	0x8000000F;	
	

	pBPMUReg->ad3sr |= 0xffffffff;	

#ifdef RTC_WAKEUP_TEST
       /* Add RTC as wakeup source for test ...*/
        rcnt = pRTC->rcnr;
	 OALMSGS(TRUE, (L"current time is %d\r\n", rcnt));
	 pRTC->rtar = rcnt + 20;
	 RT_ALARM_INT_EN(pRTC->rtsr); 
#endif
	 RT_ALARM_INT_EN(pRTC->rtsr); 

	SetWakeupSource();	
	
	/* go to Zzzz */
	//BSPPowerOff();
	OALKitlPowerOff();

    // 
    // Implements platform-specific bits just before we suspend.
    // Usually contains power optimziations that are not safely applied until this point.
    //
    if(NULL != pPlatformPreSuspend)
        (*pPlatformPreSuspend)();

#ifdef BSP_SLEEP_D0CS_WORKAROUND
    SleepWAWriteRegister((short)0x0b, "0000110000000000000000000000001" );       // Prepare for S2, workaround.
#endif

    OALMSGS(TRUE, (L"Call XllpPmEnterSleep\r\n"));	
    //OALMSGS(TRUE, (L"Dump pin values before going to sleep\r\n")); 
    //DumpMFPDomainAuto();
#if 0
	if(pCLKS->d0cken_b & 0x200)
	{
		bSideCarEnabled = TRUE;			// already enabled; no need to do anything.
	}
	else
	{
		bSideCarEnabled = FALSE;
		pCLKS->d0cken_b |= 0x200;		// It's off. Enable SideCar (usb2.0 and GCU).
		temp = pCLKS->d0cken_b;
	}

#endif
#ifdef MHLV_A2_WA_SAVE_RESTORE_OSCR0
    oscr0_saved = pOST->oscr0;
	oscr4_saved = pOST->oscr4;
#endif

    /* ****************************** ENTER D3 *********************** */
	XllpPmEnterSleep(&(g_SleepContent.PMData));                 // Enter S2, wait for wake.
    /* ****************************** EXIT D3  *********************** */

#ifdef MHLV_A2_WA_SAVE_RESTORE_OSCR0
    pOST->oscr0 = oscr0_saved ;
	pOST->oscr4 = oscr4_saved;
#endif

	*pOSCCReg |= 0x800;
#if 0    
	if(FALSE==bSideCarEnabled)
	{
		//RETAILMSG(1, (TEXT("[IPM] - Disabling sidecar\r\n")));
		pCLKS->d0cken_b &= ~0x200;		// It was off upon entry. Re-disable SideCar (usb2.0 and GCU).
		temp = pCLKS->d0cken_b;
	}
#endif

	// inside this function, it will check dbgserial enabled or not
    InitDebugSerial((UINT32) MONAHANS_BASE_REG_PA_SIRUART, FALSE);

	OALMSGS(TRUE, (L"Resume back from XllpPmEnterSleep\r\n"));

	/*Andre: disable EXT_WAKEUP0 interrupt here*/
	pSPMReg->pwer &=   ~0x1; // disable EXT_WAKEUP0 rising edge wake up
	pBPMUReg->ad3er &= ~0x1 ; //disable RTC Alarm wakeup and EXT_WAKEUP0 edge detect
	pSPMReg->pecr &= ~0x1<<28; //don't generate interrupt when EXT_WAKEUP0 pin changes

        RT_ALARM_INT_DIS(pRTC->rtsr); 

#ifdef RTC_WAKEUP_TEST
        RT_ALARM_INT_DIS(pRTC->rtsr); 
#endif

#ifdef BSP_SLEEP_D0CS_WORKAROUND	
    SleepWAWriteRegister((short)0x0b, "0000000000000000000000000000000"); // Complete S2 Exit.
#endif


	//BSPPowerOn();
//resume_back:
	

	g_oalWakeSource = GetWakeupSource();
	OALMSGS(TRUE,(L"Wakeup Source %d, AD3SR 0x%x\r\n",g_oalWakeSource, pBPMUReg->ad3sr));

	/* come back */		
	/* restore GPIO registers */	
	XllpGpioRestore(OALPAtoVA(MONAHANS_BASE_REG_PA_GPIO,FALSE), &g_SleepContent.Gpio);	
	/* :restore interrupt controller register */	
	XllpINTCRestore(OALPAtoVA(MONAHANS_BASE_REG_PA_INTC,FALSE), &(g_SleepContent.Intc));	
	/* restore OST timer registers */	
	//XllpOSTRestore(OST_BASE, &(content->ost));	
	/* restore clok manager registers */	
	XllpClockRestore(OALPAtoVA(MONAHANS_BASE_REG_PA_CLKMGR,FALSE), &(g_SleepContent.Clkmgr));
	/* some device such as PMIC will need special handle for EXT_WAKEUP[0,1]*/	

	for(i=0;i<g_SleepContent.RegCount;i++)
	{
		*g_SleepContent.RegBase[i]=g_SleepContent.SleepSave[i];
	}

	//read back to make sure all register have writen. 
	for(i=0;i<g_SleepContent.RegCount;i++)
	{
		g_SleepContent.SleepSave[i]= *g_SleepContent.RegBase[i];

	}
	
	OALKitlPowerOn();

#ifdef ENABLE_RCOMP
    // re-init the RCOMP eval, and enable RCOMP interrupt.
    memc.dmem=( XLLP_UINT32_T) OALPAtoVA(MONAHANS_BASE_REG_PA_DMEMC, FALSE);
    memc.rcEvalInterval=0x13D62; //0.2 second RCOMP updates
    memc.rcRange=2;          // resistive compensation range
    OALMSG(TRUE, (L"OEMPowerOff(): to restart the RCOMP eval, and enable RCOMP interrupts\r\n"));
    XllpMemcRcompInit(&memc);
#endif

    /* Check if it need to retore the SRAM or turn off the SRAM power */
    if (bSramEnabled)
    {
        /* Restore the SRAM content which had been used only in IMM driver */
        RestoreSRAMDataFromDDR(g_SleepContent.aucSRAMSave, sizeof(g_SleepContent.aucSRAMSave));
    }
    else
        /* turn off SRAM */
        DisableSRAM();
        
    
    // disable boot rom clock
    XllpClockEnable((P_XLLP_CLKMGR_T)pCLKS, XLLP_CLK_BOOT, XLLP_FALSE);

	//NKDbgPrintfW(TEXT("***Wakeup Source %d, AD3SR 0x%x\r\n"), g_oalWakeSource, pBPMUReg->ad3sr);

	pBPMUReg->ascr &= 0x7FFFFFFF;

	OALMSGS(TRUE, (L"Return from OEMPowerOff\r\n"));	
    
	return;
}

//------------------------------------------------------------------------------
//
// Function:     OALIoCtlHalPresuspend
//
// Description:  
//

BOOL OALIoCtlHalPresuspend(
    UINT32 code, VOID* pInpBuffer, UINT32 inpSize, VOID* pOutBuffer, 
    UINT32 outSize, UINT32 *pOutSize
) {
    return TRUE;
}


//------------------------------------------------------------------------------

